/**
 ****************************************************************************************************
 * @file        wifi_config.c
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.0
 * @date        2023-08-26
 * @brief       网络连接配置实现
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 ESP32-S3 开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 ****************************************************************************************************
 */

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_mac.h"
// #include "esp_log.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#include "Bsp.h"
#include "main.h"
#include "wifi_config.h"

/* WiFi AP config */
#define WIFI_SSID           "iProfile_text" // AP名称
#define WIFI_PASS           "12345678"      // AP密码
#define MAX_STA_CONN        4               // 最大连接数
#define UDP_PORT            2302            // UDP服务器端口

TaskHandle_t udp_thread = NULL; 		/* 任务句柄 */  //struct rt_thread iprofile_thread;
StaticTask_t udp_thread_tcb;  		/* 任务TCB */
StackType_t UDP_stack[4096];		/* 任务栈空间 */

int WIFI_Connetstatusflag = 0;
// int RealSendDataLength;
int WIFI_TransLength;
uint8_t WIFI_FirmwareVerBuf[43] = "Release-V4.18_P2.13.1-5e76b0";
uint8_t WIFI_DataBuf[160];

// extern esp_err_t spiffs_test_read(uint8_t *buffer, size_t buffer_size, size_t *bytes_read, uint32_t offset);

static frame_head_t gCommHead;
static uint8_t WIFI_MainDataBuf[64];

static const char *TAG = "wifi_ap";
// static SemaphoreHandle_t tcpip_semaphore;




static int32_t (*comm_cmd_func_cb[COMM_CMD_MAX])(frame_head_t *p_cmd_head);

void WIFIComModuleInit(void)
{
	uint16_t i;	
	for(i=0;i<COMM_CMD_MAX;i++)
	{
		comm_cmd_func_cb[i] = 0;
	}
}

int32_t WIFI_comm_command_register(uint16_t command_id,cb_command cb_func)
{
	if(command_id>COMM_CMD_MAX)
	{
		return -1;
	}
	
	comm_cmd_func_cb[command_id] = cb_func;
	return 0;
}

/* 解析数据框架， */
static int16_t WIFIRecvDataFrame(void)
{
	uint8_t ret = 0;
	uint8_t cmd_id;
	uint8_t RecvDataLength;
	uint8_t DataLen;
	uint8_t CRC8 = 0xFF;
    int i;

	RecvDataLength = WIFI_TransLength;  // 如果粘包会导致数据过长
	if((RecvDataLength>64)||(RecvDataLength<4))
	{
		ret = CMD_ERROR;
		goto frame_recv_error;
	}

	gCommHead.pDataBuf = WIFI_MainDataBuf;
	
	gCommHead.Command = WIFI_DataBuf[0];   		// 3b
	gCommHead.Proces = WIFI_DataBuf[1];			// 01
	gCommHead.DataLength = WIFI_DataBuf[2];		// 08
	gCommHead.DeviceStatus = WIFI_DataBuf[3];	// 00
	DataLen = gCommHead.DataLength;

	if(DataLen>59)
	{
		ret = CMD_ERROR;
		goto frame_recv_error;
	}
	
	if(CRC8Software(WIFI_DataBuf,RecvDataLength) != 0) 
	{		
		ret = CMD_ERROR;
		goto frame_recv_error;
	}
    
	{
		cmd_id = gCommHead.Command;
	
		if(cmd_id>=COMM_CMD_MAX)
		{		
			ret = CMD_UNSUPPORT;
			goto frame_recv_error;
		}
		
		if(comm_cmd_func_cb[cmd_id]==0)
		{
			ret = CMD_UNSUPPORT;
			goto frame_recv_error;
		}
		
		for(i=0;i<DataLen;i++)
		{
			gCommHead.pDataBuf[i] = WIFI_DataBuf[4+i];   // 将剩余结尾数存放在pDataBuf
		}
		
		// 调用函数处理gCommHead，并将结构体数据更新成发送数据
		if(comm_cmd_func_cb[gCommHead.Command](&gCommHead) == 3)
		{
			
		}
		
		WIFI_DataBuf[0] = gCommHead.Command;
		WIFI_DataBuf[1] = gCommHead.Proces;
		WIFI_DataBuf[2] = gCommHead.DataLength;   // WIFI_DataBuf[2] = 240
		WIFI_DataBuf[3] = gCommHead.DeviceStatus;
		
//		if(gCommHead.DataLength>59)
//		{
//			ret = CMD_ERROR;
//			goto frame_recv_error;
//		}
		
		// if(WIFI_DataBuf[0] == 0x3B && WIFI_DataBuf[1] == 0x01)
		// 	RealSendDataLength = gCommHead.DataLength * 2;  // 获取真正长度字节
		// else
		// 	RealSendDataLength = gCommHead.DataLength;
		
		for(i=0; i<gCommHead.DataLength; i++)
		{
			WIFI_DataBuf[4+i] = gCommHead.pDataBuf[i];		//   
		}
		
		CRC8 = CRC8Software(WIFI_DataBuf,gCommHead.DataLength + 4);
		WIFI_DataBuf[gCommHead.DataLength + 4] = CRC8; // 第15位数 16
		WIFI_TransLength = gCommHead.DataLength + 5;
        
//		iProfile.sys_status.HostConnect=1;

		return 0;
	}
	
frame_recv_error:

	//WIFI_DataBuf[0] = USB_BulkWriteBuf[0];
	//WIFI_DataBuf[1] = USB_BulkWriteBuf[1];
	//WIFI_DataBuf[2] = 0;
	WIFI_DataBuf[3] = ret;
	
	CRC8 = CRC8Software(WIFI_DataBuf,4);
	WIFI_DataBuf[4] = CRC8;
	
//	USB_Trans_CmdBuf(WIFI_DataBuf,gCommHead.DataLength + 5);
				
	return -1;
	
}

//// 将单个字节的高 4 位和低 4 位转换为 16 进制字符
//static void byte_to_hex(unsigned char byte, char *hex_str) {
//    const char hex_digits[] = "0123456789ABCDEF"; // 16 进制字符表
//    hex_str[0] = hex_digits[(byte >> 4) & 0xF];   // 高 4 位
//    hex_str[1] = hex_digits[byte & 0xF];          // 低 4 位
//}
//
//// 将字符数组转换为 16 进制字符数组
//static void chars_to_hex(const char *input, char *output, size_t len) {
//    for (size_t i = 0; i < len; i++) {
//        byte_to_hex(input[i], &output[i * 2]); // 每个字符转换为 2 个 16 进制字符
//    }
//}

/**
 * @brief WiFi事件处理函数
 * 
 * 此函数是ESP32 WiFi事件的回调处理函数，用于响应WiFi接入点模式下的客户端连接和断开事件
 * 
 * @param arg 事件处理函数的用户参数（此实现中未使用）
 * @param event_base 事件基础（标识事件来源，此处为WiFi_EVENT）
 * @param event_id 事件ID（标识具体发生的WiFi事件类型）
 * @param event_data 事件数据指针，包含事件的详细信息
 */
static void 
wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
    // 当有客户端连接到ESP32的WiFi接入点时触发
    if (event_id == WIFI_EVENT_AP_STACONNECTED)
    {
        // 类型转换，获取连接事件的详细信息
        wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
        // 打印客户端连接信息，包括MAC地址和AID（接入ID）
        // ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
        //          MAC2STR(event->mac), event->aid);
    }
    // 当有客户端断开与ESP32的WiFi接入点连接时触发
    else if (event_id == WIFI_EVENT_AP_STADISCONNECTED)
    {
        // 类型转换，获取断开连接事件的详细信息
        wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
        // 打印客户端断开连接信息，包括MAC地址和AID
        // ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
        //          MAC2STR(event->mac), event->aid);
    }
}

/**
 * UDP服务器任务函数
 * 功能：创建UDP服务器，监听指定端口，接收并处理来自客户端的命令
 * 参数：pvParameters - FreeRTOS任务标准参数，本任务未使用
 */
void udp_server_task(void *pvParameters)
{
    int sock = -1;

    char ptempbuffer[160];          // 接收数据缓冲区    
    // char addr_str[128];             // IP地址字符串缓冲区
    // uint8_t file_buffer[500];       // 文件数据缓冲区

    // 外层主循环：确保服务器在发生错误时能够重启
    while (1) {
        struct sockaddr_in dest_addr;  // 目标地址结构体
        dest_addr.sin_family = AF_INET;                 // 设置为IPv4地址族 
        dest_addr.sin_port = htons(UDP_PORT);           // 设置UDP端口号（转换为网络字节序）
        dest_addr.sin_addr.s_addr = htonl(INADDR_ANY);  // 监听所有可用网卡接口
        
        // inet_ntoa_r(dest_addr.sin_addr, addr_str, sizeof(addr_str) - 1);  // 将IP地址转换为字符串
        
        // 创建UDP套接字
        // 参数1: 地址族（IPv4）
        // 参数2: 套接字类型（SOCK_DGRAM表示UDP）
        // 参数3: IP协议
        sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
        if (sock < 0) {
            vTaskDelay(1000 / portTICK_PERIOD_MS);  // 创建失败时延迟1秒后重试
            continue;
        }
        
        // 设置套接字选项：允许地址重用，避免端口被占用的错误
        int opt = 1;
        setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
        
        // 绑定套接字到指定端口和地址
        int err = bind(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
        if (err < 0) {
        }
        struct sockaddr_in source_addr;  // 存储发送方地址信息
        socklen_t socklen = sizeof(source_addr);  // 地址结构体大小
        
        // 内层循环：持续接收和处理UDP数据
        while (1) {

            // 接收UDP数据包
            // 参数1: 套接字描述符
            // 参数2: 接收缓冲区
            // 参数3: 缓冲区大小
            // 参数4: 接收标志（0表示默认）
            // 参数5: 源地址结构体指针
            // 参数6: 源地址结构体大小指针
            int len = recvfrom(sock, ptempbuffer, 64, 0, 
                              (struct sockaddr *)&source_addr, &socklen);
            
        // // 处理接收到的数据
        // if (len < 0) {
        //     ESP_LOGE(TAG, "接收数据失败: errno %d", errno);
        //     break;  // 接收失败时退出内层循环，重新创建套接字
        // } else if (len == 0) {
        //     ESP_LOGW(TAG, "接收到空数据");
        //     continue;  // 空数据时继续等待下一个数据包
        // } else {
        //if(len == 5){
        //    // 确保字符串以null结尾，防止字符串操作时越界
        //    ptempbuffer[len] = 0;
        //    
        //    // // 将发送方IP地址转换为可读字符串
        //    // inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr.s_addr, 
        //    //             addr_str, sizeof(addr_str) - 1);
        //    
        //    // // 记录接收到的数据信息
        //    // ESP_LOGI(TAG, "接收到来自 %s:%d 的数据: %s", addr_str, 
        //    //          ntohs(((struct sockaddr_in *)&source_addr)->sin_port), ptempbuffer);
        //    
        //    if (strstr(ptempbuffer, "readr") != NULL) {
        //        // ESP_LOGI(TAG, "接收到read命令，开始读取SD卡文件...");
//
        //        size_t bytes_read = 500;
        //        uint32_t offset = 0;
        //        esp_err_t result = ESP_OK;
        //        
        //        // 循环读取文件，直到全部读取完成
        //        do {
        //            // 每次读取最多1024字节
        //            // result = spiffs_test_read(file_buffer, sizeof(file_buffer), &bytes_read, offset);
        //            
        //            if (result == ESP_OK && bytes_read > 0) {
        //                // 发送读取到的数据
        //                int send_len = sendto(sock, file_buffer, bytes_read, 0, 
        //                                    (struct sockaddr *)&source_addr, sizeof(source_addr));
        //                
        //                offset += bytes_read;
        //                // if (send_len < 0) {
        //                //     ESP_LOGE(TAG, "发送数据失败: errno %d", errno);
        //                //     break;
        //                // }
        //                
        //                // ESP_LOGI(TAG, "发送了 %d 字节数据", send_len);
        //                
        //            } else {
        //                break;
        //            }
        //        } while (bytes_read-- > 0);
        //        
        //        // // 发送文件结束标记
        //        // const char *end_msg = "FILE_END";
        //        // sendto(sock, end_msg, strlen(end_msg), 0, 
        //        //        (struct sockaddr *)&source_addr, sizeof(source_addr));
        //        
        //        // ESP_LOGI(TAG, "文件读取完成，共发送 %d 字节数据", (int)offset);
        //    }
            if (len <= 64)
            {
                
                WIFI_TransLength = len;

                // 拷贝数据 方便 WIFIRecvDataFrame 使用
                for (int i = 0; i < len; i++)
                    WIFI_DataBuf[i] = ptempbuffer[i];

                // 获取数据，处理数据，返回需要发送数据
                WIFIRecvDataFrame();

                // 处理成存储16进制 的字符串		
                // chars_to_hex((char *)WIFI_DataBuf, ptempbuffer, RealSendDataLength + 5);  // 改成16进制存储
                // WIFI_TransLength = (RealSendDataLength + 5) * 2;		// 获取数据总长

                // 发送响应数据给客户端,数据长度在WIFIRecvDataFrame（）已修改
                sendto(sock, WIFI_DataBuf, WIFI_TransLength, 0, 
                                (struct sockaddr *)&source_addr, socklen);
            }
        }
    }
    
    // 确保套接字被正确关闭，然后重新启动服务器
    if (sock != -1) {
        shutdown(sock, 0);  // 关闭套接字的发送和接收功能
        close(sock);        // 释放套接字资源
    }
}

/**
 * @brief 初始化WiFi AP模式并启动UDP服务器
 * 
 * 此函数完成以下任务：
 * 1. 创建TCP/IP信号量
 * 2. 初始化网络接口和事件循环
 * 3. 创建默认WiFi接入点
 * 4. 配置WiFi AP参数(SSID、密码等)
 * 5. 启动WiFi服务
 * 6. 创建UDP服务器任务
 */
void wifi_ap_init(void)
{
    // // 创建TCP/IP信号量，用于同步网络初始化
    // tcpip_semaphore = xSemaphoreCreateBinary();
    
    // 初始化网络接口
    ESP_ERROR_CHECK(esp_netif_init());
    // 创建默认事件循环
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    // 创建默认WiFi接入点网络接口 （ip和子网掩码）
    esp_netif_t *ap_netif = esp_netif_create_default_wifi_ap();
    // 配置AP的IP地址、网关、子网掩码
    esp_netif_ip_info_t ip_info;
    IP4_ADDR(&ip_info.ip, 192, 168, 43, 1);      // 设置IP地址为192.168.4.1
    IP4_ADDR(&ip_info.gw, 192, 168, 43, 1);      // 设置网关为192.168.4.1
    IP4_ADDR(&ip_info.netmask, 255, 255, 255, 0); // 设置子网掩码为255.255.255.0

        // 设置AP的网络接口的IP信息
    esp_netif_dhcps_stop(ap_netif); // 停止DHCP服务器
    esp_netif_set_ip_info(ap_netif, &ip_info); // 设置静态IP
    esp_netif_dhcps_start(ap_netif); // 重新启动DHCP服务器

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
    
    // 注册WiFi事件处理函数，监听所有WiFi事件
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, 
                                                        ESP_EVENT_ANY_ID, 
                                                        &wifi_event_handler, 
                                                        NULL, 
                                                        NULL));
    
    // 配置WiFi AP参数
    wifi_config_t wifi_config = {
        .ap = {
            .ssid = WIFI_SSID,              // WiFi名称
            .ssid_len = strlen(WIFI_SSID),  // WiFi名称长度
            .password = WIFI_PASS,          // WiFi密码
            .max_connection = MAX_STA_CONN, // 最大连接数
            .authmode = WIFI_AUTH_WPA_WPA2_PSK // 认证模式
        },
    };
    
    // 如果密码为空，设置为开放网络
    if (strlen(WIFI_PASS) == 0) {
        wifi_config.ap.authmode = WIFI_AUTH_OPEN;
    }
    
    // 设置WiFi模式为接入点模式
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    // 应用WiFi AP配置
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
    // 启动WiFi
    ESP_ERROR_CHECK(esp_wifi_start());
    
    // 创建UDP服务器任务，优先级为5，栈大小4096字节
    udp_thread = xTaskCreateStatic(udp_server_task, "udp_server", sizeof(UDP_stack)/sizeof(StackType_t), NULL, 21, UDP_stack, &udp_thread_tcb);
    if(udp_thread == NULL)
	{
		//Error_Handler();
        while(1);
	}
}

